﻿// <copyright file="KinectService.cs" company="Ucaya">
// </copyright>
// <author>Ucaya</author>

namespace KinectExtensions.Services
{
    #region

    using System;
    using System.ComponentModel.Composition;
    using System.Threading;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;

    using KinectExtensions.Nui;

    using Microsoft.Research.Kinect.Nui;

    #endregion

    /// <summary>
    ///   TODO: Update summary.
    /// </summary>
    [Export]
    public class KinectService
    {
        #region Constants and Fields

        /// <summary>
        ///   The is enabled.
        /// </summary>
        private bool isEnabled;

        /// <summary>
        ///   The is initialized.
        /// </summary>
        private int isInitialized;

        /// <summary>
        ///   The kinect runtime.
        /// </summary>
        private Runtime kinectRuntime;

        private Point lastMousePoint;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "KinectService" /> class.
        /// </summary>
        public KinectService()
        {
            this.KinectRuntime = new Runtime();

            ServiceLocator.Instance.SatisfyImportsOnce(this);
            this.InteractionManager.CurrentInteractionModeChanged += delegate
                {
                    this.IsEnabled = this.InteractionManager.CurrentInteractionMode == Interactions.Kinect;
                };

            CompositionTarget.Rendering += this.MainWindowRendering;

            this.lastMousePoint = InputManager.Current.PrimaryMouseDevice.GetPosition(Application.Current.MainWindow);
        }

        /// <summary>
        ///   Finalizes an instance of the <see cref = "KinectService" /> class.
        /// </summary>
        ~KinectService()
        {
            if (Application.Current == null)
            {
                return;
            }

            if (this.kinectRuntime != null && this.isInitialized != 0)
            {
                this.kinectRuntime.Uninitialize();
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets InteractionManager.
        /// </summary>
        [Import]
        public InteractionManager InteractionManager { get; set; }

        /// <summary>
        ///   Gets or sets a value indicating whether IsEnabled.
        /// </summary>
        public bool IsEnabled
        {
            get
            {
                return this.isEnabled;
            }

            set
            {
                if (this.isEnabled != value)
                {
                    this.isEnabled = value;
                }
            }
        }

        /// <summary>
        ///   Gets KinectRuntime.
        /// </summary>
        public Runtime KinectRuntime
        {
            get
            {
                if (Interlocked.Exchange(ref this.isInitialized, 1) == 0)
                {
                    this.Initialize();
                }

                return this.kinectRuntime;
            }

            private set
            {
                this.kinectRuntime = value;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        ///   The initialize.
        /// </summary>
        public void Initialize()
        {
            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }

            this.KinectRuntime.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);

            this.KinectRuntime.SkeletonEngine.TransformSmooth = true;
            var parameters = new TransformSmoothParameters { Smoothing = 0.3f, Correction = 0.0f, Prediction = 0.0f, JitterRadius = 1.0f, MaxDeviationRadius = 0.5f };
            this.KinectRuntime.SkeletonEngine.SmoothParameters = parameters;
        }

        #endregion

        #region Methods

        private void MainWindowRendering(object sender, EventArgs e)
        {
            if (Application.Current.MainWindow != null)
            {
                CompositionTarget.Rendering -= this.MainWindowRendering;

                Application.Current.MainWindow.AddHandler(UIElement.MouseMoveEvent, new MouseEventHandler(delegate
                    {
                        Point pt = InputManager.Current.PrimaryMouseDevice.GetPosition(Application.Current.MainWindow);
                        if (pt != this.lastMousePoint)
                        {
                            this.InteractionManager.CurrentInteractionMode = Interactions.Mouse;
                        }

                        this.lastMousePoint = pt;
                    }), true);

                Application.Current.MainWindow.AddHandler(UIElement.MouseDownEvent, new MouseButtonEventHandler(delegate
                    {
                        this.InteractionManager.CurrentInteractionMode = Interactions.Mouse;
                    }), true);

                Application.Current.MainWindow.AddHandler(UIElement.TouchMoveEvent, new EventHandler<TouchEventArgs>(delegate
                    {
                        this.InteractionManager.CurrentInteractionMode = Interactions.Mouse;
                    }), true);

                Application.Current.MainWindow.AddHandler(UIElement.TouchDownEvent, new EventHandler<TouchEventArgs>(delegate
                    {
                        this.InteractionManager.CurrentInteractionMode = Interactions.Mouse;
                    }), true);
            }
        }

        #endregion
    }
}